package com.demo.security.utils.jackson;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.fasterxml.jackson.core.JsonGenerator.Feature;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.SimpleType;
import com.fasterxml.jackson.databind.type.TypeBindings;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.LRUMap;

/**
 * 使用Jackson序列化Java对象
 * 
 * Jackson序列化的流程简单描述可以如下：<br>
 * 
 * 1 创建ObjectWriter()对象<br>
 * 2 使用SerializerProvider查找匹配序列化对象value的clazz对应的JsonSerializer类型<br>
 * 2.1 如果找到匹配的JsonSerializer则跳转到 5<br>
 * 2.2 如果没有找到匹配的JsonSerializer，则到3<br>
 * 3 使用TypeFactory寻找与clazz对应的JavaType<br>
 * 3.1 如果找到JavaType则跳转到 4<br>
 * 3.2 如果未找到，则通过TypeFactory创建一个新的JavaType<br>
 * 4 通过JavaType创建与之对应的JsonSerializer<br>
 * 5 调用serialize.serialize(T value, JsonGenerator gen, SerializerProvider serializers)方法进行序列化。<br>
 * 
 * @author OL
 *
 */
public class JacksonUtils {

    private JacksonUtils() {
    }

    final static ObjectMapper mapper = new ObjectMapper();

    // 自定义排序(作用在类上)
    // @JsonPropertyOrder({"id", "name"})

    // 按字母排序(任何没有显式设置的属性)(作用在类上)
    // @JsonPropertyOrder（alphabetic=true）

    static {
        // ObjectMapper序列化时的属性
        // 当遇到未知属性（没有映射到属性，没有任何setter或者任何可以处理它的handler，是否应该抛出JsonMappingException异常
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 对map排序，默认false
        mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
        // 按字母顺序排序属性,默认false(对map无效)
        mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
        // 是否允许单引号来包住属性名称和字符串值
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        // 是否允许JSON字符串包含非引号控制字符(值小于32的ASCII)@deprecated
        // mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, @deprecated);
        // 是否允许JSON整数以多个0开始deprecated
        // mapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, false);
        // 是否以类名作为根元素，可以通过@JsonRootName来自定义根元素名称,默认false
        mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
        // 是否缩放排列输出,默认false
        mapper.configure(SerializationFeature.INDENT_OUTPUT, false);
        // 序列化Date日期时以timestamps输出，默认true
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
        // 序列化枚举是否以toString()来输出，默认false，即默认以name()来输出
        mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, false);
        // 序列化枚举是否以ordinal()来输出，默认false
        mapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX, false);
        // 序列化单元素数组时不以数组来输出，默认false
        mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, false);
        // 序列化char[]时以json数组输出，默认false
        mapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS, false);
        // 序列化BigDecimal时是输出原始数字还是科学计数，默认false，即以toPlainString()科学计数方式来输出
        mapper.configure(Feature.WRITE_BIGDECIMAL_AS_PLAIN, false);
        // 是否允许解析使用Java/C++ 样式的注释（包括'/'+'*' 和'//' 变量）
        mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, false);
        // null的属性不序列化
        // mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        // ObjectMapper 反序列化的属性
        // 当遇到未知属性（没有映射到属性，没有任何setter或者任何可以处理它的handler，是否应该抛出JsonMappingException异常
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 该特性决定对于json浮点数，是否使用BigDecimal来序列化。如果不允许，则使用Double序列化。 默认为false
        mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, false);
        // 该特性决定对于json整形（非浮点），是否使用BigInteger来序列化。如果不允许，则根据数值大小来确定 是使用Integer或者Long
        mapper.configure(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS, false);
        // 该特性决定JSON ARRAY是映射为Object[]还是List<Object>。如果开启，都为Object[]，false时，则使用List 默认为false
        mapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, false);
        // 是否使用Enum.toString()的值对jsonstring进行反序列化。这个的设置和WRITE_ENUMS_USING_TO_STRING需要一致。
        mapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, false);
        // 反序列化是是否允许属性名称不带双引号
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

        // 指定Properties对象的TypeFactory
        // com.fasterxml.jackson.databind.type.TypeFactory#_fromClass()方法中，有如下代码：
        // if (rawType == Properties.class) {
        // result = MapType.construct(rawType, bindings, superClass, superInterfaces,
        // CORE_TYPE_STRING, CORE_TYPE_STRING);
        // }
        // Jackson在这里做了特殊处理，默认properties的key和value类型都是String类型，都是用StringSerializer
        SimpleType keyType = SimpleType.constructUnsafe(String.class);
        SimpleType valueType = SimpleType.constructUnsafe(Object.class);
        // TypeBindings bindings = TypeBindings.create(Properties.class, keyType,
        // valueType);
        TypeBindings bindings = TypeBindings.emptyBindings();
        JavaType superClass = TypeFactory.unknownType();
        MapType propertiesType = MapType.construct(Properties.class, bindings, superClass, null, keyType, valueType);
        // 新建propertiesType,并添加至typeFactory的_typeCache缓存中
        LRUMap<Object, JavaType> cache = new LRUMap<Object, JavaType>(16, 200);
        cache.put(Properties.class, propertiesType);
        TypeFactory typeFactory = TypeFactory.defaultInstance().withCache(cache);
        mapper.setTypeFactory(typeFactory);
    }

    /**
     * Json序列化
     * 
     * @param obj
     * @return
     */
    public static String toJsonString(Object obj) {
        // ObjectMapper mapper = new ObjectMapper();
        try {
            // mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json序列化异常.", e);
        }
    }

    /**
     * Json序列化
     * 
     * @param obj
     * @param order 是否排序
     * @return
     */
    public static String toJsonString(Object obj, boolean order) {
        if (order) {
            return toJsonString(obj);
        }
        ObjectMapper mapper = new ObjectMapper();
        try {
            mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json序列化异常.", e);
        }
    }

    /**
     * Json字符串转JsonNode对象
     * 
     * @param json
     * @return
     */
    public static JsonNode toJsonNode(String json) {
        // ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readTree(json);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json字符串解析异常.", e);
        }
    }

    /**
     * Json字符串转Jackson对象
     * 
     * @param json
     * @return
     */
    public static JacksonObject toJsonObject(String json) {
        // ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(json, JacksonObject.class);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json字符串解析异常.", e);
        }
    }

    /**
     * Java对象转Jackson对象
     * 
     * @param object
     * @return
     */
    public static JacksonObject toJsonObject(Object object) {
        // ObjectMapper mapper = new ObjectMapper();
        return mapper.convertValue(object, JacksonObject.class);
    }

    /**
     * Json字符串转Json数组
     * 
     * @param json
     * @return
     */
    public static JacksonArray toJsonArray(String json) {
        // ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(json, JacksonArray.class);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json字符串解析异常.", e);
        }
    }

    /**
     * Json字符串转Java对象
     * 
     * @param <T>
     * @param json
     * @param clazz
     * @return
     */
    public static <T> T toObject(String json, Class<T> clazz) {
        // ObjectMapper mapper = new ObjectMapper();
        try {
            // mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            return mapper.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json字符串解析异常.", e);
        }
    }

    /**
     * JsonNode转Java对象
     * 
     * @param <T>
     * @param json
     * @param clazz
     * @return
     */
    public static <T> T toObject(JsonNode node, Class<T> clazz) {
        // ObjectMapper mapper = new ObjectMapper();
        // mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper.convertValue(node, clazz);
    }

    /**
     * Json对象串转Java对象
     * 
     * @param <T>
     * @param json
     * @param clazz
     * @return
     */
    public static <T> T toObject(JacksonObject obj, Class<T> clazz) {
        // ObjectMapper mapper = new ObjectMapper();
        try {
            // mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            return mapper.readValue(obj.toString(), clazz);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json字符串解析异常.", e);
        }
    }

    /**
     * Json字符串转Map
     * 
     * @param <M>
     * @param <V>
     * @param <K>
     * @param json
     * @param m    Map的类型:HashMap/TreeMap等
     * @param k    Map.key的泛型类型
     * @param v    Map.value的泛型类型
     * @return
     */
    public static <M extends Map<?, ?>, V, K> Map<K, V> toMap(String json, Class<M> m, Class<K> k, Class<V> v) {
        // ObjectMapper mapper = new ObjectMapper();
        JavaType javaType = mapper.getTypeFactory().constructParametricType(m, k, v);
        try {
            return mapper.readValue(json, javaType);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json字符串解析异常.", e);
        }
    }

    /**
     * Json字符串转HashMap<String, Object>
     * 
     * @param json
     * @return
     */
    public static HashMap<String, Object> toHashMap(String json) {
        // ObjectMapper mapper = new ObjectMapper();
        JavaType javaType = mapper.getTypeFactory().constructParametricType(HashMap.class, String.class, Object.class);
        try {
            return mapper.readValue(json, javaType);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json字符串解析异常.", e);
        }
    }

    /**
     * Json字符串转List
     * 
     * @param <L>
     * @param <T>
     * @param json
     * @param l    List的类型: ArrayList/LinkedList等
     * @param t    List的泛型类型
     * @return
     */
    public static <L extends List<?>, T> List<T> toList(String json, Class<L> l, Class<T> t) {
        // ObjectMapper mapper = new ObjectMapper();
        JavaType javaType = mapper.getTypeFactory().constructParametricType(l, t);
        try {
            return mapper.readValue(json, javaType);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json字符串解析异常.", e);
        }
    }

    /**
     * Json字符串转ArrayList
     * 
     * @param json
     * @return
     */
    public static ArrayList<Object> toArrayList(String json) {
        // ObjectMapper mapper = new ObjectMapper();
        JavaType javaType = mapper.getTypeFactory().constructParametricType(ArrayList.class, Object.class);
        try {
            return mapper.readValue(json, javaType);
        } catch (JsonProcessingException e) {
            throw new JacksonException("Json字符串解析异常.", e);
        }
    }

    /**
     * JsonNode转Map
     * 
     * @param jsonNode
     * @return
     */
    public static <T> T jsonNodeToObject(JsonNode jsonNode, Class<T> clazz) {
        // ObjectMapper mapper = new ObjectMapper();
        // mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper.convertValue(jsonNode, clazz);
    }

    public static <M extends Map<?, ?>, V, K> Map<K, V> jsonNodeToMap(JsonNode jsonNode, Class<M> m, Class<K> k, Class<V> v) {
        // ObjectMapper mapper = new ObjectMapper();
        JavaType javaType = mapper.getTypeFactory().constructParametricType(m, k, v);
        return mapper.convertValue(jsonNode, javaType);
    }

    /**
     * JsonNode转HashMap
     * 
     * @param jsonNode
     * @return
     */
    public static HashMap<String, Object> jsonNodeToHashMap(JsonNode jsonNode) {
        // ObjectMapper mapper = new ObjectMapper();
        JavaType javaType = mapper.getTypeFactory().constructParametricType(HashMap.class, String.class, Object.class);
        HashMap<String, Object> map = mapper.convertValue(jsonNode, javaType);
        return map;
    }

}
